package dy.app.interceptor;

import dy.app.base.JsonResult;
import dy.app.component.RedisCacheComponent;
import dy.app.constant.GlobalConstant;
import dy.app.constant.TimeConstant;
import dy.app.dto.InterceptorDto;
import dy.app.enums.BizCodeEnum;
import dy.app.enums.CacheKeyEnums;
import dy.app.util.CommonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 登录拦截器逻辑 此为具体逻辑 拦截可在具体微服务,自定义调用
 * Author: cKnight
 * Date: 2024/6/11
 */
@Slf4j
public class LoginInterceptor implements HandlerInterceptor{
    public static final ThreadLocal<InterceptorDto> loginThreadlocal = new ThreadLocal<>();

    @Resource
    private RedisCacheComponent redisCacheComponent;
    /**
     * 前置拦截器
     * @param request current HTTP request
     * @param response current HTTP response
     * @param handler chosen handler to execute, for type and/or instance evaluation
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //略过测试请求
        if (HttpMethod.OPTIONS.toString().equalsIgnoreCase(request.getMethod())){
            response.setStatus(HttpStatus.NO_CONTENT.value());
            log.info("拦截器,拦截测试,url:{}",request.getRequestURI());
            return true;
        }
        //判断 url 是否符合要求
        if (checkUrl(request.getRequestURI())){
            //非法请求
            log.error("拦截器,拦截非法请求,url:{}",request.getRequestURI());
            CommonUtils.sendJsonMessage(response, JsonResult.buildResult(BizCodeEnum.ILLEGAL_REQUEST));
            return false;
        }
        //根据 url判断 走不同逻辑
        if (request.getRequestURI().contains(GlobalConstant.URL_ADMIN)){
            //后管逻辑
            return adminProcess(request,response);
        }else if (request.getRequestURI().contains(GlobalConstant.URL_API)){
            //小程序逻辑
            return apiProcess(request,response);
        }

        return false;
    }

    /**
     * 小程序处理逻辑
     *
     * @param request
     * @param response
     * @return
     */
    private boolean apiProcess(HttpServletRequest request, HttpServletResponse response) {
        String openId = request.getHeader(GlobalConstant.OPEN_ID);
        if (StringUtils.isBlank(openId)){
            return resultProcess(false,response,BizCodeEnum.APP_USER_LOGIN_EXPIRE);
        }
        //缓存存在则延期不存在则略过
        String key = String.format(CacheKeyEnums.APP_LOGIN_KEY.getKey(), openId);
        String cache = redisCacheComponent.get(key);
        if (StringUtils.isNoneBlank(cache)){
            //延期
            redisCacheComponent.set(key,cache, TimeConstant.ONE_HOUR);
        }
        //放入 threadLocal
        loginThreadlocal.set(InterceptorDto.builder().openId(openId).build());
        return true;
    }

    /**
     * 后管处理逻辑
     *
     * @param request
     * @param response
     * @return
     */
    private boolean adminProcess(HttpServletRequest request, HttpServletResponse response) {
        String token = request.getHeader(GlobalConstant.ADMIN_TOKEN);
        if (StringUtils.isBlank(token)){
            return resultProcess(false,response,BizCodeEnum.SYS_USER_LOGIN_EXPIRE);
        }
        //判断 token 是否过期
        String cache = redisCacheComponent.get(String.format(CacheKeyEnums.ADMIN_LOGIN_KEY.getKey(),token));
        if (StringUtils.isBlank(cache)){
            return resultProcess(false,response, BizCodeEnum.SYS_USER_LOGIN_EXPIRE);
        }
        //对token延期 并加入 threadLocal
        delayToken(token,cache);
        return true;
    }

    /**
     * 延期 token 加入threadLocal
     *
     * @param token
     * @param cache
     */
    private void delayToken(String token, String cache) {
        //延期一小时
        redisCacheComponent.set(String.format(CacheKeyEnums.ADMIN_LOGIN_KEY.getKey(),token),cache, TimeConstant.ONE_HOUR);
        loginThreadlocal.set(InterceptorDto.builder().adminToken(token).build());
    }

    /**
     * 处理 result
     *
     * @param result
     * @param response
     * @param bizCodeEnum
     * @return
     */
    private boolean resultProcess(boolean result, HttpServletResponse response, BizCodeEnum bizCodeEnum) {
        if (result){
            return result;
        }
        CommonUtils.sendJsonMessage(response, JsonResult.buildResult(bizCodeEnum));
        return false;
    }

    /**
     * 判断是否是非法url
     * @param requestURI
     * @return
     */
    private boolean checkUrl(String requestURI) {
        if (requestURI.contains(GlobalConstant.URL_ADMIN)
                || requestURI.contains(GlobalConstant.URL_API)
                || requestURI.contains(GlobalConstant.URL_SWAGGER)){
            return false;
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //后置操作
        loginThreadlocal.remove();
    }
}
